/*
 * File     : CallbackRecord.java
 * Created  : 6 Jan 2012
 *
 * Copyright © 2011 Matthew Wilson (mj. {my-surname} .uk {at} gmail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.dni.internal.callback;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import com.googlecode.dni.library.CallingConvention;

/**
 * <p>
 *  Holds information about a call-back.
 * </p>
 * <p>
 *  The record's key is its defining interface type.  DNI provides an
 *  implementation type that serves two purposes:  Firstly, it is a concrete
 *  type that calls to a native function (the address of which is a constructor
 *  argument).  Secondly, it has a static helper method that is called from the
 *  native thunk to dispatch the call to the correctly typed call-back.
 * </p>
 *
 * @param <T>
 *            the interface type
 *
 * @author Matthew Wilson
 */
final class CallbackRecord< T >
{

    private final Class< ? extends T > type;

    private final CallingConvention callingConvention;

    private final Class< ? extends T > implType;

    private final Method helperMethod;

    /**
     * @param type
     *            the interface type
     * @param callingConvention
     *            the calling convention
     * @param implType
     *            the implementation type
     * @param helperMethod
     *            the helper method
     */
    CallbackRecord( final Class< ? extends T > type,
                    final CallingConvention callingConvention,
                    final Class< ? extends T > implType,
                    final Method helperMethod )
    {
        assert type.isAssignableFrom( implType );
        assert type.isInterface();
        assert !implType.isInterface();
        assert Modifier.isAbstract( implType.getModifiers() );
        assert helperMethod.getDeclaringClass() == implType;

        this.type = type;
        this.callingConvention = callingConvention;
        this.implType = implType;
        this.helperMethod = helperMethod;
    }

    /**
     * @return the interface type
     */
    public Class< ? extends T > getType()
    {
        return this.type;
    }

    /**
     * @return the calling convention
     */
    public CallingConvention getCallingContention()
    {
        return this.callingConvention;
    }

    /**
     * <p>
     *  Obtains the implementation type.
     * </p>
     * <p>
     *  This concrete class serves two purposes:  Firstly, instances act as
     *  delegates for native function pointers; that is, there is a constructor
     *  that takes a pointer and the delegate's method is implemented.
     *  Secondly, there is a static helper method that is called from native
     *  code to dispatch the method call to the correct Java method.
     * </p>
     *
     * @return the implementation type
     */
    public Class< ? extends T > getImplType()
    {
        return this.implType;
    }

    /**
     * @return the static helper method
     */
    public Method getHelperMethod()
    {
        return this.helperMethod;
    }

    /** {@inheritDoc} */
    @Override
    public String toString()
    {
        return "CallbackRecord[" + this.type.getName() + "," + this.implType.getName() + "]";
    }

}
